<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>继承</title>
</head>
<body>

</body>
<script>
    //继承: 子类继承父类中的属性和方法
    {//原型链继承
        /*function Person() {//父类
            this.name = "tutu";
        }

        Person.prototype.getName = function () {
            console.log(this.name);
        };

        function Child() {

        }

        Child.prototype = new Person();
        var child = new Child();
        child.getName(); //tutu
        console.log(child);
        console.log(child.name);*/
    }
    {//原型链继承
        // 缺点 1.引用类型的属性被所有实例共享
        //     2.在创建Child的实例时, 不能向Person传参
        /*function Person(name) {//父类
            this.name = name || "tutu";
            this.friends = ["dage","baoer","erha"];
        }

        Person.prototype.getName = function () {
            console.log(this.name);
        };

        function Child() {

        }

        Child.prototype = new Person();
        var child1 = new Child("tieZhu");
        var child2 = new Child("tieChui");
//        child.getName(); //tutu
        console.log(child1);
        console.log(child2);
        child1.friends.push("tieDanEr");
        console.log(child1.friends);
        console.log(child2.friends);*/
    }

    {//call继承 构造函数继承
        /*function Person(name) {//父类
            this.name = name || "tutu";
            this.friends = ["dage","baoer","erha"];
        }

        Person.prototype.getName = function () {
            console.log(this.name);
        };

        function Child(name) {

            Person.call(this, name);
        }

        var child1 = new Child("tieZhu");
        var child2 = new Child("tieChui");
//        child.getName(); //tutu
        console.log(child1.name);
        console.log(child2.name);
        child1.friends.push("tieDanEr");
        console.log(child1.friends);
        console.log(child2.friends);
        console.log(child1 instanceof Person);//false 不是Person的实例*/

//        child1.getName()

        //优点: 1.避免了引用类型的属性被所有实例共享
        //     2.可以在Child中向Parent传参
        //缺点: 1.方法都在构造函数中定义, 所以每次创建实例都会创建一遍方法
        //     2.只是子类的实例,不是父类的实例
        //     3.不能使用父类的方法
    }
    {//组合继承
        //组合 原型链继承 和借用构造函数继承(call继承)
        //思路: 使用原型链实现对原型方法的继承, 通过call继承实现对实例属性的继承

       /* function Parent(name) {
            this.name = name || "tutu";
            this.friends = ["dage","baoer","erha"];
        }

        Parent.prototype.getName = function () {
            console.log(this.name);
        };

        function Child(name, age){
            Parent.call(this, name); //通过call继承实现对实例属性的继承 调用了一次父类构造函数
            this.age = age;
        }
        Child.prototype = new Parent();//使用原型链实现对原型方法的继承 又调用了一次父类构造函数

        var child1 = new Child("tieZhu", 18);
        var child2 = new Child("tieChui", 19);
        child1.getName();//tieZhu
        child2.getName();//tieChui
        console.log(child1.age);//18
        console.log(child2.age);//19
        console.log(child2);//19
        child1.friends.push("tieDanEr");
        console.log(child1.friends);//["dage", "baoer", "erha", "tieDanEr"]
        console.log(child2.friends);//["dage", "baoer", "erha"]
        console.log(child1 instanceof Child);//true
        console.log(child1 instanceof Parent);//true*/
        //优点: 融合了原型链继承和构造函数继承的优点, 一般情况下组合继承是最常用的继承模式
        //缺点: 调用了两次父类构造函数
        //     组合继承最大的缺点就是无论在什么情况下,都会调用两次父类构造函数; 一次是在创建子类原型的时候,另一次是在子类构造函数内部
    }
    {//寄生式继承
        let ob = {
            name: "tutu",
            friends: ["dage","baoer","erha"]
        };
        function CreateObj(o) {
            var newOb = Object.create(o);

            console.log(newOb);
            console.log({});
            newOb.sayName = function () {
                console.log(this.name);
            };
            return newOb
        }

        let ob1 = CreateObj(ob);
        let ob2 = CreateObj(ob);

        console.log(ob1.name);
        console.log(ob2.name);
        ob1.sayName();
    }
    {//寄生组合继承 最完美的继承方式
        function Parent(name) {
            this.name = name || "tutu";
            this.friends = ["dage","baoer","erha"];
        }

        Parent.prototype.getName = function () {
            console.log(this.name);
        };

        function Child(name, age){
            Parent.call(this, name); //通过call继承实现对实例属性的继承 调用了一次父类构造函数
            this.age = age;
        }
        Child.prototype = new Parent();//使用原型链实现对原型方法的继承 又调用了一次父类构造函数

        function CreateObj(o) {
            function F() {}
            F.prototype = o;
            return new F();
        }

        function prototype(child, parent) {
            var prototype = CreateObj(parent.prototype);
            prototype.constructor = child;
            child.prototype = prototype
        }
        prototype(Child, Parent);

        var child1 = new Child("tieZhu", 18);
        var child2 = new Child("tieChui", 19);


    }


















</script>
</html>